package asteroids.model;

import asteroids.CollisionListener;

/**
 * @version 0.3
 * @author  Tandan Sunil, Van Deun Luca
 */
public class Asteroid extends Entity{

	/**
	 * Initialize this new asteroid with given coordinates and speed according to x- and y- axes, radius and direction.
	 *  
	 * @param  xCoordinate 
	 * 		   The x-coordinate for this new entity in kilometers.
	 * @param  yCoordinate
	 * 		   The y-coordinate for this new entity in kilometers.
	 * @param  xVelocity
	 * 		   The initial velocity for this new entity according to the x-axis in kilometers/second.
	 * @param  yVelocity
	 * 	       The initial velocity for this new entity according to the y-axis in kilometers/second.
	 * @param  radius
	 * 		   The radius for this new circular entity in kilometers. 		   
	 * @pre	   The given radius must be a valid radius for a entity.
	 * 		 | isValidRadius(radius)
	 * @pre	   The total speed of this new entity must be valid.
	 * 	 	 | isValidVelocity((Math.sqrt(Math.pow(xVelocity, 2)+Math.pow(yVelocity,2)))) 
	 * @post   The new entity has the given x-coordinate.
	 * 		 | new.getXCoordinate() == xCoordinate
	 * @post   The new entity has the given y-coordinate.
	 * 		 | new.getYCoordinate() == yCoordinate
	 * @post   The new entity has the given radius.
	 * 		 | new.getRadius() == radius
	 * @post   ...
	 * 		 | new.getMass() == 4/3*Math.PI*Math.pow(radius, 3)*asteroidDensity
	 * @effect The given velocities are set as the new velocities of this new entity.
	 * 		 | setVelocity(xVelocity,yVelocity)
	 * @throws IllegalArgumentException
	 * 		   The given radius is invalid.
	 * 		 | ! isValidRadius(radius)
	 * @throws IllegalArgumentException
	 * 		   The given coordinate is invalid.
	 * 		 | ! isValidCoordinate(xCoordinate) || ! isValidCoordinate(yCoordinate)
	 *
	 */
	public Asteroid(double xCoordinate, double yCoordinate, double xVelocity, double yVelocity, double radius){
		super(xCoordinate, yCoordinate, xVelocity, yVelocity, radius, 4/3*Math.PI*Math.pow(radius, 3)*asteroidDensity);
	}
	
	
	public static final double asteroidDensity = 2.65 * Math.pow(10,12); //in kg/km^3 
	
	/**
	 * @post ...
	 * 		|if(getRadius()<30)
	 * 		| then this.terminate();
	 * 		|else
	 * 		|  childAsteroid = new Asteroid(getXCoordinate() + getRadius()/2* Math.cos(random), 
	 *		|		        getYCoordinate() + getRadius()/2* Math.sin(random), 1.5 * getTotalVelocity()
	 *		|				* Math.cos(random), 1.5 * getTotalVelocity()
	 *		|				* Math.sin(random), getRadius() / 2);
	 *		|  childAsteroid2 = new Asteroid(getXCoordinate() - getRadius()/2* Math.cos(random),
	 *		|				getYCoordinate() - getRadius()/2* Math.sin(random), -1.5 * getTotalVelocity()
	 *		|				* Math.cos(random), -1.5 * getTotalVelocity()
	 *      |				* Math.sin(random), getRadius() / 2);
	 *      |  this.getWorld().contains(childAsteroid) && this.getWorld().contains(childAsteroid2)
	 * 		|  this.terminate()
	 */
	@Override
	public void die(){
		if(getRadius() >30){
			double random = Math.random() * (2 * Math.PI);
			Asteroid childAsteroid = new Asteroid(getXCoordinate() + getRadius()/2* Math.cos(random), 
					        getYCoordinate() + getRadius()/2* Math.sin(random), 1.5 * getTotalVelocity()
							* Math.cos(random), 1.5 * getTotalVelocity()
							* Math.sin(random), getRadius() / 2);
			Asteroid childAsteroid2 = new Asteroid(getXCoordinate() - getRadius()/2* Math.cos(random),
					getYCoordinate() - getRadius()/2* Math.sin(random), -1.5 * getTotalVelocity()
					* Math.cos(random), -1.5 * getTotalVelocity()
					* Math.sin(random), getRadius() / 2);
			World world = this.getWorld();
			this.terminate();
			world.addAsEntity(childAsteroid);
			world.addAsEntity(childAsteroid2);
			
			}
		this.terminate();
	}
	
	
	
	
	////////////////////////////////////////////////////////////////////////////
	//								Collision   							  //
	////////////////////////////////////////////////////////////////////////////
	
	
	/**
	 * Returns true only if entity is this asteroid.
	 * @param entity
	 * 		  The entity to be checked.
	 * @pre   The given entity is valid.
	 * 	      | Entity.isValidEntity(entity1)
	 * @return  ...
	 * 		  | result == ( this == entity)
	 * 			
	 */
	@Override
	public boolean isRelated(Entity entity){
		assert(Entity.isValidEntity(entity));
		return this==entity;
	}

	/**
	 * Checks whether the given entity is able to bounce with this Asteroid.
	 * @param	entity1
	 * 			The entity with which it has to be checked.
	 * @pre  	The given entity is valid.
	 * 			| Entity.isValidEntity(entity1)
	 * @return  ...
	 * 			| 	if(entity1 instanceof Asteroid)
	 *			| 		then result== true;
	 *			|   else if(entity1 instanceof Ship)
	 *			|  		then result == false;
	 *		 	|  	else result == entity1.canBounceWith(this);
     *	
	 */
	@Override
	public boolean canBounceWith(Entity entity1) {
		assert(Entity.isValidEntity(entity1));
		if(entity1 instanceof Asteroid)
			return true;
		else if(entity1 instanceof Ship)
			return false;
		else return entity1.canBounceWith(this);
	}
	/**
	 * Resolves the collision between this entity and the given entity.
	 * @param	 other
	 * 			| The entity with which the collision occurs.
	 * @param 	collisionListener
	 * 			|  The collision listener that has to be called.
	 * @pre   The given entity is valid.
	 * 		  | Entity.isValidEntity(other)
	 * @effect   If this canBounceWith(entity2) then collideBounce(entity2)
	 * 			|if(canBounceWith(entity2))
	 * 			| then this.collideBounce(entity2)
	 * @effect  If other is instance of ship then ship dies.
	 * 			| if(other instanceof Ship) then other.die().
	 * @effect  If this cannot bounce with other and other is not instance of ship then other.collide.
	 * 			| if(!canBounceWith(other) && !(other instanceof Ship))
	 * 			| 		then other.collide(this,collisionListener)
	 */
	@Override
	public void collide(Entity other, CollisionListener collisionListener) {
		assert(Entity.isValidEntity(other));
		if(canBounceWith(other)){
			collideBounce(other);
		}
		else if (other instanceof Ship){
			other.die();
		}
		else
			other.collide(this, collisionListener);
		
	}
}
